// vim:set sw=4 sts=4 et cin:/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"nsSocketTransportService2.h"#include"nsSocketTransport2.h"#include"NetworkActivityMonitor.h"#include"mozilla/IntegerPrintfMacros.h"#include"mozilla/Preferences.h"#include"nsIOService.h"#include"nsASocketHandler.h"#include"nsError.h"#include"prnetdb.h"#include"prerror.h"#include"nsIPrefService.h"#include"nsIPrefBranch.h"#include"nsServiceManagerUtils.h"#include"nsIObserverService.h"#include"mozilla/Atomics.h"#include"mozilla/Services.h"#include"mozilla/Likely.h"#include"mozilla/PublicSSL.h"#include"mozilla/ChaosMode.h"#include"mozilla/PodOperations.h"#include"mozilla/Telemetry.h"#include"nsThreadUtils.h"#include"nsIFile.h"#include"nsIWidget.h"#include"mozilla/dom/FlyWebService.h"#ifdef MOZ_TASK_TRACER#include"GeckoTaskTracer.h"#endifnamespacemozilla{namespacenet{LazyLogModulegSocketTransportLog("nsSocketTransport");LazyLogModulegUDPSocketLog("UDPSocket");LazyLogModulegTCPSocketLog("TCPSocket");nsSocketTransportService*gSocketTransportService=nullptr;staticAtomic<PRThread*,Relaxed>gSocketThread;#define SEND_BUFFER_PREF "network.tcp.sendbuffer"#define KEEPALIVE_ENABLED_PREF "network.tcp.keepalive.enabled"#define KEEPALIVE_IDLE_TIME_PREF "network.tcp.keepalive.idle_time"#define KEEPALIVE_RETRY_INTERVAL_PREF "network.tcp.keepalive.retry_interval"#define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count"#define SOCKET_LIMIT_TARGET 1000U#define SOCKET_LIMIT_MIN 50U#define BLIP_INTERVAL_PREF "network.activity.blipIntervalMilliseconds"#define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls"#define TELEMETRY_PREF "toolkit.telemetry.enabled"#define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown"#define REPAIR_POLLABLE_EVENT_TIME 10uint32_tnsSocketTransportService::gMaxCount;PRCallOnceTypensSocketTransportService::gMaxCountInitOnce;// Utility functionsboolOnSocketThread(){returnPR_GetCurrentThread()==gSocketThread;}//-----------------------------------------------------------------------------// ctor/dtor (called on the main/UI thread by the service manager)nsSocketTransportService::nsSocketTransportService():mThread(nullptr),mLock("nsSocketTransportService::mLock"),mInitialized(false),mShuttingDown(false),mOffline(false),mGoingOffline(false),mRawThread(nullptr),mActiveListSize(SOCKET_LIMIT_MIN),mIdleListSize(SOCKET_LIMIT_MIN),mActiveCount(0),mIdleCount(0),mSentBytesCount(0),mReceivedBytesCount(0),mSendBufferSize(0),mKeepaliveIdleTimeS(600),mKeepaliveRetryIntervalS(1),mKeepaliveProbeCount(kDefaultTCPKeepCount),mKeepaliveEnabledPref(false),mServingPendingQueue(false),mMaxTimePerPollIter(100),mTelemetryEnabledPref(false),mMaxTimeForPrClosePref(PR_SecondsToInterval(5)),mSleepPhase(false),mProbedMaxCount(false)#if defined(XP_WIN),mPolling(false)#endif{NS_ASSERTION(NS_IsMainThread(),"wrong thread");PR_CallOnce(&gMaxCountInitOnce,DiscoverMaxCount);mActiveList=(SocketContext*)moz_xmalloc(sizeof(SocketContext)*mActiveListSize);mIdleList=(SocketContext*)moz_xmalloc(sizeof(SocketContext)*mIdleListSize);mPollList=(PRPollDesc*)moz_xmalloc(sizeof(PRPollDesc)*(mActiveListSize+1));NS_ASSERTION(!gSocketTransportService,"must not instantiate twice");gSocketTransportService=this;}nsSocketTransportService::~nsSocketTransportService(){NS_ASSERTION(NS_IsMainThread(),"wrong thread");NS_ASSERTION(!mInitialized,"not shutdown properly");free(mActiveList);free(mIdleList);free(mPollList);gSocketTransportService=nullptr;}//-----------------------------------------------------------------------------// event queue (any thread)already_AddRefed<nsIThread>nsSocketTransportService::GetThreadSafely(){MutexAutoLocklock(mLock);nsCOMPtr<nsIThread>result=mThread;returnresult.forget();}NS_IMETHODIMPnsSocketTransportService::DispatchFromScript(nsIRunnable*event,uint32_tflags){nsCOMPtr<nsIRunnable>event_ref(event);returnDispatch(event_ref.forget(),flags);}NS_IMETHODIMPnsSocketTransportService::Dispatch(already_AddRefed<nsIRunnable>event,uint32_tflags){nsCOMPtr<nsIRunnable>event_ref(event);SOCKET_LOG(("STS dispatch [%p]\n",event_ref.get()));nsCOMPtr<nsIThread>thread=GetThreadSafely();nsresultrv;rv=thread?thread->Dispatch(event_ref.forget(),flags):NS_ERROR_NOT_INITIALIZED;if(rv==NS_ERROR_UNEXPECTED){// Thread is no longer accepting events. We must have just shut it// down on the main thread. Pretend we never saw it.rv=NS_ERROR_NOT_INITIALIZED;}returnrv;}NS_IMETHODIMPnsSocketTransportService::DelayedDispatch(already_AddRefed<nsIRunnable>,uint32_t){returnNS_ERROR_NOT_IMPLEMENTED;}NS_IMETHODIMPnsSocketTransportService::IsOnCurrentThread(bool*result){nsCOMPtr<nsIThread>thread=GetThreadSafely();NS_ENSURE_TRUE(thread,NS_ERROR_NOT_INITIALIZED);returnthread->IsOnCurrentThread(result);}NS_IMETHODIMP_(bool)nsSocketTransportService::IsOnCurrentThreadInfallible(){nsCOMPtr<nsIThread>thread=GetThreadSafely();NS_ENSURE_TRUE(thread,false);returnthread->IsOnCurrentThread();}//-----------------------------------------------------------------------------// socket api (socket thread only)NS_IMETHODIMPnsSocketTransportService::NotifyWhenCanAttachSocket(nsIRunnable*event){SOCKET_LOG(("nsSocketTransportService::NotifyWhenCanAttachSocket\n"));MOZ_ASSERT(OnSocketThread(),"not on socket thread");if(CanAttachSocket()){returnDispatch(event,NS_DISPATCH_NORMAL);}auto*runnable=newLinkedRunnableEvent(event);mPendingSocketQueue.insertBack(runnable);returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::AttachSocket(PRFileDesc*fd,nsASocketHandler*handler){SOCKET_LOG(("nsSocketTransportService::AttachSocket [handler=%p]\n",handler));MOZ_ASSERT(OnSocketThread(),"not on socket thread");if(!CanAttachSocket()){returnNS_ERROR_NOT_AVAILABLE;}SocketContextsock;sock.mFD=fd;sock.mHandler=handler;sock.mElapsedTime=0;nsresultrv=AddToIdleList(&sock);if(NS_SUCCEEDED(rv))NS_ADDREF(handler);returnrv;}// the number of sockets that can be attached at any given time is// limited. this is done because some operating systems (e.g., Win9x)// limit the number of sockets that can be created by an application.// AttachSocket will fail if the limit is exceeded. consumers should// call CanAttachSocket and check the result before creating a socket.boolnsSocketTransportService::CanAttachSocket(){staticboolreported900FDLimit=false;uint32_ttotal=mActiveCount+mIdleCount;boolrv=total<gMaxCount;if(mTelemetryEnabledPref&&(((total>=900)||!rv)&&!reported900FDLimit)){reported900FDLimit=true;Telemetry::Accumulate(Telemetry::NETWORK_SESSION_AT_900FD,true);}returnrv;}nsresultnsSocketTransportService::DetachSocket(SocketContext*listHead,SocketContext*sock){SOCKET_LOG(("nsSocketTransportService::DetachSocket [handler=%p]\n",sock->mHandler));MOZ_ASSERT((listHead==mActiveList)||(listHead==mIdleList),"DetachSocket invalid head");{#ifdef MOZ_TASK_TRACERtasktracer::AutoSourceEventtaskTracerEvent(tasktracer::SourceEventType::SocketIO);#endif// inform the handler that this socket is going awaysock->mHandler->OnSocketDetached(sock->mFD);}mSentBytesCount+=sock->mHandler->ByteCountSent();mReceivedBytesCount+=sock->mHandler->ByteCountReceived();// cleanupsock->mFD=nullptr;NS_RELEASE(sock->mHandler);if(listHead==mActiveList)RemoveFromPollList(sock);elseRemoveFromIdleList(sock);// NOTE: sock is now an invalid pointer//// notify the first element on the pending socket queue...//nsCOMPtr<nsIRunnable>event;LinkedRunnableEvent*runnable=mPendingSocketQueue.getFirst();if(runnable){event=runnable->TakeEvent();runnable->remove();deleterunnable;}if(event){// move event from pending queue to dispatch queuereturnDispatch(event,NS_DISPATCH_NORMAL);}returnNS_OK;}nsresultnsSocketTransportService::AddToPollList(SocketContext*sock){MOZ_ASSERT(!(static_cast<uint32_t>(sock-mActiveList)<mActiveListSize),"AddToPollList Socket Already Active");SOCKET_LOG(("nsSocketTransportService::AddToPollList [handler=%p]\n",sock->mHandler));if(mActiveCount==mActiveListSize){SOCKET_LOG((" Active List size of %d met\n",mActiveCount));if(!GrowActiveList()){NS_ERROR("too many active sockets");returnNS_ERROR_OUT_OF_MEMORY;}}uint32_tnewSocketIndex=mActiveCount;if(ChaosMode::isActive(ChaosFeature::NetworkScheduling)){newSocketIndex=ChaosMode::randomUint32LessThan(mActiveCount+1);PodMove(mActiveList+newSocketIndex+1,mActiveList+newSocketIndex,mActiveCount-newSocketIndex);PodMove(mPollList+newSocketIndex+2,mPollList+newSocketIndex+1,mActiveCount-newSocketIndex);}mActiveList[newSocketIndex]=*sock;mActiveCount++;mPollList[newSocketIndex+1].fd=sock->mFD;mPollList[newSocketIndex+1].in_flags=sock->mHandler->mPollFlags;mPollList[newSocketIndex+1].out_flags=0;SOCKET_LOG((" active=%u idle=%u\n",mActiveCount,mIdleCount));returnNS_OK;}voidnsSocketTransportService::RemoveFromPollList(SocketContext*sock){SOCKET_LOG(("nsSocketTransportService::RemoveFromPollList [handler=%p]\n",sock->mHandler));uint32_tindex=sock-mActiveList;MOZ_ASSERT(index<mActiveListSize,"invalid index");SOCKET_LOG((" index=%u mActiveCount=%u\n",index,mActiveCount));if(index!=mActiveCount-1){mActiveList[index]=mActiveList[mActiveCount-1];mPollList[index+1]=mPollList[mActiveCount];}mActiveCount--;SOCKET_LOG((" active=%u idle=%u\n",mActiveCount,mIdleCount));}nsresultnsSocketTransportService::AddToIdleList(SocketContext*sock){MOZ_ASSERT(!(static_cast<uint32_t>(sock-mIdleList)<mIdleListSize),"AddToIdlelList Socket Already Idle");SOCKET_LOG(("nsSocketTransportService::AddToIdleList [handler=%p]\n",sock->mHandler));if(mIdleCount==mIdleListSize){SOCKET_LOG((" Idle List size of %d met\n",mIdleCount));if(!GrowIdleList()){NS_ERROR("too many idle sockets");returnNS_ERROR_OUT_OF_MEMORY;}}mIdleList[mIdleCount]=*sock;mIdleCount++;SOCKET_LOG((" active=%u idle=%u\n",mActiveCount,mIdleCount));returnNS_OK;}voidnsSocketTransportService::RemoveFromIdleList(SocketContext*sock){SOCKET_LOG(("nsSocketTransportService::RemoveFromIdleList [handler=%p]\n",sock->mHandler));uint32_tindex=sock-mIdleList;NS_ASSERTION(index<mIdleListSize,"invalid index in idle list");if(index!=mIdleCount-1)mIdleList[index]=mIdleList[mIdleCount-1];mIdleCount--;SOCKET_LOG((" active=%u idle=%u\n",mActiveCount,mIdleCount));}voidnsSocketTransportService::MoveToIdleList(SocketContext*sock){nsresultrv=AddToIdleList(sock);if(NS_FAILED(rv))DetachSocket(mActiveList,sock);elseRemoveFromPollList(sock);}voidnsSocketTransportService::MoveToPollList(SocketContext*sock){nsresultrv=AddToPollList(sock);if(NS_FAILED(rv))DetachSocket(mIdleList,sock);elseRemoveFromIdleList(sock);}boolnsSocketTransportService::GrowActiveList(){int32_ttoAdd=gMaxCount-mActiveListSize;if(toAdd>100){toAdd=100;}elseif(toAdd<1){MOZ_ASSERT(false,"CanAttachSocket() should prevent this");returnfalse;}mActiveListSize+=toAdd;mActiveList=(SocketContext*)moz_xrealloc(mActiveList,sizeof(SocketContext)*mActiveListSize);mPollList=(PRPollDesc*)moz_xrealloc(mPollList,sizeof(PRPollDesc)*(mActiveListSize+1));returntrue;}boolnsSocketTransportService::GrowIdleList(){int32_ttoAdd=gMaxCount-mIdleListSize;if(toAdd>100){toAdd=100;}elseif(toAdd<1){MOZ_ASSERT(false,"CanAttachSocket() should prevent this");returnfalse;}mIdleListSize+=toAdd;mIdleList=(SocketContext*)moz_xrealloc(mIdleList,sizeof(SocketContext)*mIdleListSize);returntrue;}PRIntervalTimensSocketTransportService::PollTimeout(){if(mActiveCount==0)returnNS_SOCKET_POLL_TIMEOUT;// compute minimum time before any socket timeout expires.uint32_tminR=UINT16_MAX;for(uint32_ti=0;i<mActiveCount;++i){constSocketContext&s=mActiveList[i];// mPollTimeout could be less than mElapsedTime if setTimeout// was called with a value smaller than mElapsedTime.uint32_tr=(s.mElapsedTime<s.mHandler->mPollTimeout)?s.mHandler->mPollTimeout-s.mElapsedTime:0;if(r<minR)minR=r;}// nsASocketHandler defines UINT16_MAX as do not timeoutif(minR==UINT16_MAX){SOCKET_LOG(("poll timeout: none\n"));returnNS_SOCKET_POLL_TIMEOUT;}SOCKET_LOG(("poll timeout: %"PRIu32"\n",minR));returnPR_SecondsToInterval(minR);}int32_tnsSocketTransportService::Poll(uint32_t*interval,TimeDuration*pollDuration){PRPollDesc*pollList;uint32_tpollCount;PRIntervalTimepollTimeout;*pollDuration=0;// If there are pending events for this thread then// DoPollIteration() should service the network without blocking.boolpendingEvents=false;mRawThread->HasPendingEvents(&pendingEvents);if(mPollList[0].fd){mPollList[0].out_flags=0;pollList=mPollList;pollCount=mActiveCount+1;pollTimeout=pendingEvents?PR_INTERVAL_NO_WAIT:PollTimeout();}else{// no pollable event, so busy wait...pollCount=mActiveCount;if(pollCount)pollList=&mPollList[1];elsepollList=nullptr;pollTimeout=pendingEvents?PR_INTERVAL_NO_WAIT:PR_MillisecondsToInterval(25);}PRIntervalTimets=PR_IntervalNow();TimeStamppollStart;if(mTelemetryEnabledPref){pollStart=TimeStamp::NowLoRes();}SOCKET_LOG((" timeout = %i milliseconds\n",PR_IntervalToMilliseconds(pollTimeout)));int32_trv=PR_Poll(pollList,pollCount,pollTimeout);PRIntervalTimepassedInterval=PR_IntervalNow()-ts;if(mTelemetryEnabledPref&&!pollStart.IsNull()){*pollDuration=TimeStamp::NowLoRes()-pollStart;}SOCKET_LOG((" ...returned after %i milliseconds\n",PR_IntervalToMilliseconds(passedInterval)));*interval=PR_IntervalToSeconds(passedInterval);returnrv;}//-----------------------------------------------------------------------------// xpcom apiNS_IMPL_ISUPPORTS(nsSocketTransportService,nsISocketTransportService,nsIRoutedSocketTransportService,nsIEventTarget,nsIThreadObserver,nsIRunnable,nsPISocketTransportService,nsIObserver)// called from main thread onlyNS_IMETHODIMPnsSocketTransportService::Init(){if(!NS_IsMainThread()){NS_ERROR("wrong thread");returnNS_ERROR_UNEXPECTED;}if(mInitialized)returnNS_OK;if(mShuttingDown)returnNS_ERROR_UNEXPECTED;nsCOMPtr<nsIThread>thread;nsresultrv=NS_NewNamedThread("Socket Thread",getter_AddRefs(thread),this);if(NS_FAILED(rv))returnrv;{MutexAutoLocklock(mLock);// Install our mThread, protecting against concurrent readersthread.swap(mThread);}nsCOMPtr<nsIPrefBranch>tmpPrefService=do_GetService(NS_PREFSERVICE_CONTRACTID);if(tmpPrefService){tmpPrefService->AddObserver(SEND_BUFFER_PREF,this,false);tmpPrefService->AddObserver(KEEPALIVE_ENABLED_PREF,this,false);tmpPrefService->AddObserver(KEEPALIVE_IDLE_TIME_PREF,this,false);tmpPrefService->AddObserver(KEEPALIVE_RETRY_INTERVAL_PREF,this,false);tmpPrefService->AddObserver(KEEPALIVE_PROBE_COUNT_PREF,this,false);tmpPrefService->AddObserver(MAX_TIME_BETWEEN_TWO_POLLS,this,false);tmpPrefService->AddObserver(TELEMETRY_PREF,this,false);tmpPrefService->AddObserver(MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN,this,false);}UpdatePrefs();nsCOMPtr<nsIObserverService>obsSvc=services::GetObserverService();if(obsSvc){obsSvc->AddObserver(this,"profile-initial-state",false);obsSvc->AddObserver(this,"last-pb-context-exited",false);obsSvc->AddObserver(this,NS_WIDGET_SLEEP_OBSERVER_TOPIC,true);obsSvc->AddObserver(this,NS_WIDGET_WAKE_OBSERVER_TOPIC,true);obsSvc->AddObserver(this,"xpcom-shutdown-threads",false);}mInitialized=true;returnNS_OK;}// called from main thread onlyNS_IMETHODIMPnsSocketTransportService::Shutdown(boolaXpcomShutdown){SOCKET_LOG(("nsSocketTransportService::Shutdown\n"));NS_ENSURE_STATE(NS_IsMainThread());if(!mInitialized)returnNS_OK;if(mShuttingDown)returnNS_ERROR_UNEXPECTED;{MutexAutoLocklock(mLock);// signal the socket thread to shutdownmShuttingDown=true;if(mPollableEvent){mPollableEvent->Signal();}}if(!aXpcomShutdown){returnShutdownThread();}returnNS_OK;}nsresultnsSocketTransportService::ShutdownThread(){SOCKET_LOG(("nsSocketTransportService::ShutdownThread\n"));NS_ENSURE_STATE(NS_IsMainThread());if(!mInitialized||!mShuttingDown)returnNS_OK;// join with threadmThread->Shutdown();{MutexAutoLocklock(mLock);// Drop our reference to mThread and make sure that any concurrent// readers are excludedmThread=nullptr;}nsCOMPtr<nsIPrefBranch>tmpPrefService=do_GetService(NS_PREFSERVICE_CONTRACTID);if(tmpPrefService)tmpPrefService->RemoveObserver(SEND_BUFFER_PREF,this);nsCOMPtr<nsIObserverService>obsSvc=services::GetObserverService();if(obsSvc){obsSvc->RemoveObserver(this,"profile-initial-state");obsSvc->RemoveObserver(this,"last-pb-context-exited");obsSvc->RemoveObserver(this,NS_WIDGET_SLEEP_OBSERVER_TOPIC);obsSvc->RemoveObserver(this,NS_WIDGET_WAKE_OBSERVER_TOPIC);obsSvc->RemoveObserver(this,"xpcom-shutdown-threads");}if(mAfterWakeUpTimer){mAfterWakeUpTimer->Cancel();mAfterWakeUpTimer=nullptr;}NetworkActivityMonitor::Shutdown();mInitialized=false;mShuttingDown=false;returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::GetOffline(bool*offline){*offline=mOffline;returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::SetOffline(booloffline){MutexAutoLocklock(mLock);if(!mOffline&&offline){// signal the socket thread to go offline, so it will detach socketsmGoingOffline=true;mOffline=true;}elseif(mOffline&&!offline){mOffline=false;}if(mPollableEvent){mPollableEvent->Signal();}returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::GetKeepaliveIdleTime(int32_t*aKeepaliveIdleTimeS){MOZ_ASSERT(aKeepaliveIdleTimeS);if(NS_WARN_IF(!aKeepaliveIdleTimeS)){returnNS_ERROR_NULL_POINTER;}*aKeepaliveIdleTimeS=mKeepaliveIdleTimeS;returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::GetKeepaliveRetryInterval(int32_t*aKeepaliveRetryIntervalS){MOZ_ASSERT(aKeepaliveRetryIntervalS);if(NS_WARN_IF(!aKeepaliveRetryIntervalS)){returnNS_ERROR_NULL_POINTER;}*aKeepaliveRetryIntervalS=mKeepaliveRetryIntervalS;returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::GetKeepaliveProbeCount(int32_t*aKeepaliveProbeCount){MOZ_ASSERT(aKeepaliveProbeCount);if(NS_WARN_IF(!aKeepaliveProbeCount)){returnNS_ERROR_NULL_POINTER;}*aKeepaliveProbeCount=mKeepaliveProbeCount;returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::CreateTransport(constchar**types,uint32_ttypeCount,constnsACString&host,int32_tport,nsIProxyInfo*proxyInfo,nsISocketTransport**result){returnCreateRoutedTransport(types,typeCount,host,port,NS_LITERAL_CSTRING(""),0,proxyInfo,result);}NS_IMETHODIMPnsSocketTransportService::CreateRoutedTransport(constchar**types,uint32_ttypeCount,constnsACString&host,int32_tport,constnsACString&hostRoute,int32_tportRoute,nsIProxyInfo*proxyInfo,nsISocketTransport**result){// Check FlyWeb table for host mappings. If one exists, then use that.RefPtr<mozilla::dom::FlyWebService>fws=mozilla::dom::FlyWebService::GetExisting();if(fws){nsresultrv=fws->CreateTransportForHost(types,typeCount,host,port,hostRoute,portRoute,proxyInfo,result);NS_ENSURE_SUCCESS(rv,rv);if(*result){returnNS_OK;}}NS_ENSURE_TRUE(mInitialized,NS_ERROR_NOT_INITIALIZED);NS_ENSURE_TRUE(port>=0&&port<=0xFFFF,NS_ERROR_ILLEGAL_VALUE);RefPtr<nsSocketTransport>trans=newnsSocketTransport();nsresultrv=trans->Init(types,typeCount,host,port,hostRoute,portRoute,proxyInfo);if(NS_FAILED(rv)){returnrv;}trans.forget(result);returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::CreateUnixDomainTransport(nsIFile*aPath,nsISocketTransport**result){nsresultrv;NS_ENSURE_TRUE(mInitialized,NS_ERROR_NOT_INITIALIZED);nsAutoCStringpath;rv=aPath->GetNativePath(path);if(NS_FAILED(rv))returnrv;RefPtr<nsSocketTransport>trans=newnsSocketTransport();rv=trans->InitWithFilename(path.get());if(NS_FAILED(rv))returnrv;trans.forget(result);returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::OnDispatchedEvent(nsIThreadInternal*thread){#ifndef XP_WIN// On windows poll can hang and this became worse when we introduced the// patch for bug 698882 (see also bug 1292181), therefore we reverted the// behavior on windows to be as before bug 698882, e.g. write to the socket// also if an event dispatch is on the socket thread and writing to the// socket for each event.if(OnSocketThread()){// this check is redundant to one done inside ::Signal(), but// we can do it here and skip obtaining the lock - given that// this is a relatively common occurance its worth the// redundant codeSOCKET_LOG(("OnDispatchedEvent Same Thread Skip Signal\n"));returnNS_OK;}#elseif(gIOService->IsNetTearingDown()){// Poll can hang sometimes. If we are in shutdown, we are going to// start a watchdog. If we do not exit poll within// REPAIR_POLLABLE_EVENT_TIME signal a pollable event again.StartPollWatchdog();}#endifMutexAutoLocklock(mLock);if(mPollableEvent){mPollableEvent->Signal();}returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::OnProcessNextEvent(nsIThreadInternal*thread,boolmayWait){returnNS_OK;}NS_IMETHODIMPnsSocketTransportService::AfterProcessNextEvent(nsIThreadInternal*thread,booleventWasProcessed){returnNS_OK;}voidnsSocketTransportService::MarkTheLastElementOfPendingQueue(){mServingPendingQueue=false;}NS_IMETHODIMPnsSocketTransportService::Run(){SOCKET_LOG(("STS thread init %d sockets\n",gMaxCount));#if defined(XP_WIN)// see bug 1361495, gethostname() triggers winsock initialization.// so do it here (on parent and child) to protect against it being done first// accidentally on the main thread.. especially via PR_GetSystemInfo(). This// will also improve latency of first real winsock operation// ..// If STS-thread is no longer needed this should still be run before exitingcharignoredStackBuffer[255];Unused<<gethostname(ignoredStackBuffer,255);#endifpsm::InitializeSSLServerCertVerificationThreads();gSocketThread=PR_GetCurrentThread();{MutexAutoLocklock(mLock);mPollableEvent.reset(newPollableEvent());//// NOTE: per bug 190000, this failure could be caused by Zone-Alarm// or similar software.//// NOTE: per bug 191739, this failure could also be caused by lack// of a loopback device on Windows and OS/2 platforms (it creates// a loopback socket pair on these platforms to implement a pollable// event object). if we can't create a pollable event, then we'll// have to "busy wait" to implement the socket event queue :-(//if(!mPollableEvent->Valid()){mPollableEvent=nullptr;NS_WARNING("running socket transport thread without a pollable event");SOCKET_LOG(("running socket transport thread without a pollable event"));}mPollList[0].fd=mPollableEvent?mPollableEvent->PollableFD():nullptr;mPollList[0].in_flags=PR_POLL_READ|PR_POLL_EXCEPT;mPollList[0].out_flags=0;}mRawThread=NS_GetCurrentThread();// hook ourselves up to observe event processing for this threadnsCOMPtr<nsIThreadInternal>threadInt=do_QueryInterface(mRawThread);threadInt->SetObserver(this);// make sure the pseudo random number generator is seeded on this threadsrand(static_cast<unsigned>(PR_Now()));// For the calculation of the duration of the last cycle (i.e. the last for-loop// iteration before shutdown).TimeStampstartOfCycleForLastCycleCalc;intnumberOfPendingEventsLastCycle;// For measuring of the poll iteration duration without time spent blocked// in poll().TimeStamppollCycleStart;// Time blocked in poll().TimeDurationsinglePollDuration;// For calculating the time needed for a new element to run.TimeStampstartOfIteration;TimeStampstartOfNextIteration;intnumberOfPendingEvents;// If there is too many pending events queued, we will run some poll()// between them and the following variable is cumulative time spent// blocking in poll().TimeDurationpollDuration;for(;;){boolpendingEvents=false;numberOfPendingEvents=0;numberOfPendingEventsLastCycle=0;if(mTelemetryEnabledPref){startOfCycleForLastCycleCalc=TimeStamp::NowLoRes();startOfNextIteration=TimeStamp::NowLoRes();}pollDuration=0;do{if(mTelemetryEnabledPref){pollCycleStart=TimeStamp::NowLoRes();}DoPollIteration(&singlePollDuration);if(mTelemetryEnabledPref&&!pollCycleStart.IsNull()){Telemetry::Accumulate(Telemetry::STS_POLL_BLOCK_TIME,singlePollDuration.ToMilliseconds());Telemetry::AccumulateTimeDelta(Telemetry::STS_POLL_CYCLE,pollCycleStart+singlePollDuration,TimeStamp::NowLoRes());pollDuration+=singlePollDuration;}mRawThread->HasPendingEvents(&pendingEvents);if(pendingEvents){if(!mServingPendingQueue){nsresultrv=Dispatch(NewRunnableMethod("net::nsSocketTransportService::""MarkTheLastElementOfPendingQueue",this,&nsSocketTransportService::MarkTheLastElementOfPendingQueue),nsIEventTarget::DISPATCH_NORMAL);if(NS_FAILED(rv)){NS_WARNING("Could not dispatch a new event on the ""socket thread.");}else{mServingPendingQueue=true;}if(mTelemetryEnabledPref){startOfIteration=startOfNextIteration;// Everything that comes after this point will// be served in the next iteration. If no even// arrives, startOfNextIteration will be reset at the// beginning of each for-loop.startOfNextIteration=TimeStamp::NowLoRes();}}TimeStampeventQueueStart=TimeStamp::NowLoRes();do{NS_ProcessNextEvent(mRawThread);numberOfPendingEvents++;pendingEvents=false;mRawThread->HasPendingEvents(&pendingEvents);}while(pendingEvents&&mServingPendingQueue&&((TimeStamp::NowLoRes()-eventQueueStart).ToMilliseconds()<mMaxTimePerPollIter));if(mTelemetryEnabledPref&&!mServingPendingQueue&&!startOfIteration.IsNull()){Telemetry::AccumulateTimeDelta(Telemetry::STS_POLL_AND_EVENTS_CYCLE,startOfIteration+pollDuration,TimeStamp::NowLoRes());Telemetry::Accumulate(Telemetry::STS_NUMBER_OF_PENDING_EVENTS,numberOfPendingEvents);numberOfPendingEventsLastCycle+=numberOfPendingEvents;numberOfPendingEvents=0;pollDuration=0;}}}while(pendingEvents);boolgoingOffline=false;// now that our event queue is empty, check to see if we should exit{MutexAutoLocklock(mLock);if(mShuttingDown){if(mTelemetryEnabledPref&&!startOfCycleForLastCycleCalc.IsNull()){Telemetry::Accumulate(Telemetry::STS_NUMBER_OF_PENDING_EVENTS_IN_THE_LAST_CYCLE,numberOfPendingEventsLastCycle);Telemetry::AccumulateTimeDelta(Telemetry::STS_POLL_AND_EVENT_THE_LAST_CYCLE,startOfCycleForLastCycleCalc,TimeStamp::NowLoRes());}break;}if(mGoingOffline){mGoingOffline=false;goingOffline=true;}}// Avoid potential deadlockif(goingOffline)Reset(true);}SOCKET_LOG(("STS shutting down thread\n"));// detach all sockets, including localsReset(false);// Final pass over the event queue. This makes sure that events posted by// socket detach handlers get processed.NS_ProcessPendingEvents(mRawThread);gSocketThread=nullptr;psm::StopSSLServerCertVerificationThreads();SOCKET_LOG(("STS thread exit\n"));returnNS_OK;}voidnsSocketTransportService::DetachSocketWithGuard(boolaGuardLocals,SocketContext*socketList,int32_tindex){boolisGuarded=false;if(aGuardLocals){socketList[index].mHandler->IsLocal(&isGuarded);if(!isGuarded)socketList[index].mHandler->KeepWhenOffline(&isGuarded);}if(!isGuarded)DetachSocket(socketList,&socketList[index]);}voidnsSocketTransportService::Reset(boolaGuardLocals){// detach any socketsint32_ti;for(i=mActiveCount-1;i>=0;--i){DetachSocketWithGuard(aGuardLocals,mActiveList,i);}for(i=mIdleCount-1;i>=0;--i){DetachSocketWithGuard(aGuardLocals,mIdleList,i);}}nsresultnsSocketTransportService::DoPollIteration(TimeDuration*pollDuration){SOCKET_LOG(("STS poll iter\n"));int32_ti,count;//// poll loop//// walk active list backwards to see if any sockets should actually be// idle, then walk the idle list backwards to see if any idle sockets// should become active. take care to check only idle sockets that// were idle to begin with ;-)//count=mIdleCount;for(i=mActiveCount-1;i>=0;--i){//---SOCKET_LOG((" active [%u] { handler=%p condition=%"PRIx32" pollflags=%hu }\n",i,mActiveList[i].mHandler,static_cast<uint32_t>(mActiveList[i].mHandler->mCondition),mActiveList[i].mHandler->mPollFlags));//---if(NS_FAILED(mActiveList[i].mHandler->mCondition))DetachSocket(mActiveList,&mActiveList[i]);else{uint16_tin_flags=mActiveList[i].mHandler->mPollFlags;if(in_flags==0)MoveToIdleList(&mActiveList[i]);else{// update poll flagsmPollList[i+1].in_flags=in_flags;mPollList[i+1].out_flags=0;}}}for(i=count-1;i>=0;--i){//---SOCKET_LOG((" idle [%u] { handler=%p condition=%"PRIx32" pollflags=%hu }\n",i,mIdleList[i].mHandler,static_cast<uint32_t>(mIdleList[i].mHandler->mCondition),mIdleList[i].mHandler->mPollFlags));//---if(NS_FAILED(mIdleList[i].mHandler->mCondition))DetachSocket(mIdleList,&mIdleList[i]);elseif(mIdleList[i].mHandler->mPollFlags!=0)MoveToPollList(&mIdleList[i]);}SOCKET_LOG((" calling PR_Poll [active=%u idle=%u]\n",mActiveCount,mIdleCount));#if defined(XP_WIN)// 30 active connections is the historic limit before firefox 7's 256. A few// windows systems have troubles with the higher limit, so actively probe a// limit the first time we exceed 30.if((mActiveCount>30)&&!mProbedMaxCount)ProbeMaxCount();#endif// Measures seconds spent while blocked on PR_Polluint32_tpollInterval=0;int32_tn=0;*pollDuration=0;if(!gIOService->IsNetTearingDown()){// Let's not do polling during shutdown.#if defined(XP_WIN)StartPolling();#endifn=Poll(&pollInterval,pollDuration);#if defined(XP_WIN)EndPolling();#endif}if(n<0){SOCKET_LOG((" PR_Poll error [%d] os error [%d]\n",PR_GetError(),PR_GetOSError()));}else{//// service "active" sockets...//uint32_tnumberOfOnSocketReadyCalls=0;for(i=0;i<int32_t(mActiveCount);++i){PRPollDesc&desc=mPollList[i+1];SocketContext&s=mActiveList[i];if(n>0&&desc.out_flags!=0){#ifdef MOZ_TASK_TRACERtasktracer::AutoSourceEventtaskTracerEvent(tasktracer::SourceEventType::SocketIO);#endifs.mElapsedTime=0;s.mHandler->OnSocketReady(desc.fd,desc.out_flags);numberOfOnSocketReadyCalls++;}// check for timeout errors unless disabled...elseif(s.mHandler->mPollTimeout!=UINT16_MAX){// update elapsed time counter// (NOTE: We explicitly cast UINT16_MAX to be an unsigned value// here -- otherwise, some compilers will treat it as signed,// which makes them fire signed/unsigned-comparison build// warnings for the comparison against 'pollInterval'.)if(MOZ_UNLIKELY(pollInterval>static_cast<uint32_t>(UINT16_MAX)-s.mElapsedTime))s.mElapsedTime=UINT16_MAX;elses.mElapsedTime+=uint16_t(pollInterval);// check for timeout expiration if(s.mElapsedTime>=s.mHandler->mPollTimeout){#ifdef MOZ_TASK_TRACERtasktracer::AutoSourceEventtaskTracerEvent(tasktracer::SourceEventType::SocketIO);#endifs.mElapsedTime=0;s.mHandler->OnSocketReady(desc.fd,-1);numberOfOnSocketReadyCalls++;}}}if(mTelemetryEnabledPref){Telemetry::Accumulate(Telemetry::STS_NUMBER_OF_ONSOCKETREADY_CALLS,numberOfOnSocketReadyCalls);}//// check for "dead" sockets and remove them (need to do this in// reverse order obviously).//for(i=mActiveCount-1;i>=0;--i){if(NS_FAILED(mActiveList[i].mHandler->mCondition))DetachSocket(mActiveList,&mActiveList[i]);}if(n!=0&&(mPollList[0].out_flags&(PR_POLL_READ|PR_POLL_EXCEPT))){MutexAutoLocklock(mLock);// acknowledge pollable event (should not block)if(mPollableEvent&&((mPollList[0].out_flags&PR_POLL_EXCEPT)||!mPollableEvent->Clear())){// On Windows, the TCP loopback connection in the// pollable event may become broken when a laptop// switches between wired and wireless networks or// wakes up from hibernation. We try to create a// new pollable event. If that fails, we fall back// on "busy wait".NS_WARNING("Trying to repair mPollableEvent");mPollableEvent.reset(newPollableEvent());if(!mPollableEvent->Valid()){mPollableEvent=nullptr;}SOCKET_LOG(("running socket transport thread without ""a pollable event now valid=%d",!!mPollableEvent));mPollList[0].fd=mPollableEvent?mPollableEvent->PollableFD():nullptr;mPollList[0].in_flags=PR_POLL_READ|PR_POLL_EXCEPT;mPollList[0].out_flags=0;}}}returnNS_OK;}voidnsSocketTransportService::UpdateSendBufferPref(nsIPrefBranch*pref){int32_tbufferSize;// If the pref is set, honor it. 0 means use OS defaults.nsresultrv=pref->GetIntPref(SEND_BUFFER_PREF,&bufferSize);if(NS_SUCCEEDED(rv)){mSendBufferSize=bufferSize;return;}#if defined(XP_WIN)mSendBufferSize=131072*4;#endif}nsresultnsSocketTransportService::UpdatePrefs(){mSendBufferSize=0;nsCOMPtr<nsIPrefBranch>tmpPrefService=do_GetService(NS_PREFSERVICE_CONTRACTID);if(tmpPrefService){UpdateSendBufferPref(tmpPrefService);// Default TCP Keepalive Values.int32_tkeepaliveIdleTimeS;nsresultrv=tmpPrefService->GetIntPref(KEEPALIVE_IDLE_TIME_PREF,&keepaliveIdleTimeS);if(NS_SUCCEEDED(rv))mKeepaliveIdleTimeS=clamped(keepaliveIdleTimeS,1,kMaxTCPKeepIdle);int32_tkeepaliveRetryIntervalS;rv=tmpPrefService->GetIntPref(KEEPALIVE_RETRY_INTERVAL_PREF,&keepaliveRetryIntervalS);if(NS_SUCCEEDED(rv))mKeepaliveRetryIntervalS=clamped(keepaliveRetryIntervalS,1,kMaxTCPKeepIntvl);int32_tkeepaliveProbeCount;rv=tmpPrefService->GetIntPref(KEEPALIVE_PROBE_COUNT_PREF,&keepaliveProbeCount);if(NS_SUCCEEDED(rv))mKeepaliveProbeCount=clamped(keepaliveProbeCount,1,kMaxTCPKeepCount);boolkeepaliveEnabled=false;rv=tmpPrefService->GetBoolPref(KEEPALIVE_ENABLED_PREF,&keepaliveEnabled);if(NS_SUCCEEDED(rv)&&keepaliveEnabled!=mKeepaliveEnabledPref){mKeepaliveEnabledPref=keepaliveEnabled;OnKeepaliveEnabledPrefChange();}int32_tmaxTimePref;rv=tmpPrefService->GetIntPref(MAX_TIME_BETWEEN_TWO_POLLS,&maxTimePref);if(NS_SUCCEEDED(rv)&&maxTimePref>=0){mMaxTimePerPollIter=maxTimePref;}booltelemetryPref=false;rv=tmpPrefService->GetBoolPref(TELEMETRY_PREF,&telemetryPref);if(NS_SUCCEEDED(rv)){mTelemetryEnabledPref=telemetryPref;}int32_tmaxTimeForPrClosePref;rv=tmpPrefService->GetIntPref(MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN,&maxTimeForPrClosePref);if(NS_SUCCEEDED(rv)&&maxTimeForPrClosePref>=0){mMaxTimeForPrClosePref=PR_MillisecondsToInterval(maxTimeForPrClosePref);}}returnNS_OK;}voidnsSocketTransportService::OnKeepaliveEnabledPrefChange(){// Dispatch to socket thread if we're not executing there.if(!OnSocketThread()){gSocketTransportService->Dispatch(NewRunnableMethod("net::nsSocketTransportService::OnKeepaliveEnabledPrefChange",this,&nsSocketTransportService::OnKeepaliveEnabledPrefChange),NS_DISPATCH_NORMAL);return;}SOCKET_LOG(("nsSocketTransportService::OnKeepaliveEnabledPrefChange %s",mKeepaliveEnabledPref?"enabled":"disabled"));// Notify each socket that keepalive has been en/disabled globally.for(int32_ti=mActiveCount-1;i>=0;--i){NotifyKeepaliveEnabledPrefChange(&mActiveList[i]);}for(int32_ti=mIdleCount-1;i>=0;--i){NotifyKeepaliveEnabledPrefChange(&mIdleList[i]);}}voidnsSocketTransportService::NotifyKeepaliveEnabledPrefChange(SocketContext*sock){MOZ_ASSERT(sock,"SocketContext cannot be null!");MOZ_ASSERT(sock->mHandler,"SocketContext does not have a handler!");if(!sock||!sock->mHandler){return;}#ifdef MOZ_TASK_TRACERtasktracer::AutoSourceEventtaskTracerEvent(tasktracer::SourceEventType::SocketIO);#endifsock->mHandler->OnKeepaliveEnabledPrefChange(mKeepaliveEnabledPref);}NS_IMETHODIMPnsSocketTransportService::Observe(nsISupports*subject,constchar*topic,constchar16_t*data){if(!strcmp(topic,NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)){UpdatePrefs();returnNS_OK;}if(!strcmp(topic,"profile-initial-state")){int32_tblipInterval=Preferences::GetInt(BLIP_INTERVAL_PREF,0);if(blipInterval<=0){returnNS_OK;}returnnet::NetworkActivityMonitor::Init(blipInterval);}if(!strcmp(topic,"last-pb-context-exited")){nsCOMPtr<nsIRunnable>ev=NewRunnableMethod("net::nsSocketTransportService::ClosePrivateConnections",this,&nsSocketTransportService::ClosePrivateConnections);nsresultrv=Dispatch(ev,nsIEventTarget::DISPATCH_NORMAL);NS_ENSURE_SUCCESS(rv,rv);}if(!strcmp(topic,NS_TIMER_CALLBACK_TOPIC)){nsCOMPtr<nsITimer>timer=do_QueryInterface(subject);if(timer==mAfterWakeUpTimer){mAfterWakeUpTimer=nullptr;mSleepPhase=false;}#if defined(XP_WIN)if(timer==mPollRepairTimer){DoPollRepair();}#endif}elseif(!strcmp(topic,NS_WIDGET_SLEEP_OBSERVER_TOPIC)){mSleepPhase=true;if(mAfterWakeUpTimer){mAfterWakeUpTimer->Cancel();mAfterWakeUpTimer=nullptr;}}elseif(!strcmp(topic,NS_WIDGET_WAKE_OBSERVER_TOPIC)){if(mSleepPhase&&!mAfterWakeUpTimer){mAfterWakeUpTimer=do_CreateInstance("@mozilla.org/timer;1");if(mAfterWakeUpTimer){mAfterWakeUpTimer->Init(this,2000,nsITimer::TYPE_ONE_SHOT);}}}elseif(!strcmp(topic,"xpcom-shutdown-threads")){ShutdownThread();}returnNS_OK;}voidnsSocketTransportService::ClosePrivateConnections(){// Must be called on the socket thread.#ifdef DEBUGboolonSTSThread;IsOnCurrentThread(&onSTSThread);MOZ_ASSERT(onSTSThread);#endiffor(int32_ti=mActiveCount-1;i>=0;--i){if(mActiveList[i].mHandler->mIsPrivate){DetachSocket(mActiveList,&mActiveList[i]);}}for(int32_ti=mIdleCount-1;i>=0;--i){if(mIdleList[i].mHandler->mIsPrivate){DetachSocket(mIdleList,&mIdleList[i]);}}ClearPrivateSSLState();}NS_IMETHODIMPnsSocketTransportService::GetSendBufferSize(int32_t*value){*value=mSendBufferSize;returnNS_OK;}/// ugly OS specific includes are placed at the bottom of the src for clarity#if defined(XP_WIN)#include<windows.h>#elif defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX)#include<sys/resource.h>#endif// Right now the only need to do this is on windows.#if defined(XP_WIN)voidnsSocketTransportService::ProbeMaxCount(){MOZ_ASSERT(OnSocketThread(),"not on socket thread");if(mProbedMaxCount)return;mProbedMaxCount=true;// Allocate and test a PR_Poll up to the gMaxCount number of unconnected// sockets. See bug 692260 - windows should be able to handle 1000 sockets// in select() without a problem, but LSPs have been known to balk at lower// numbers. (64 in the bug).// AllocatestructPRPollDescpfd[SOCKET_LIMIT_TARGET];uint32_tnumAllocated=0;for(uint32_tindex=0;index<gMaxCount;++index){pfd[index].in_flags=PR_POLL_READ|PR_POLL_WRITE|PR_POLL_EXCEPT;pfd[index].out_flags=0;pfd[index].fd=PR_OpenTCPSocket(PR_AF_INET);if(!pfd[index].fd){SOCKET_LOG(("Socket Limit Test index %d failed\n",index));if(index<SOCKET_LIMIT_MIN)gMaxCount=SOCKET_LIMIT_MIN;elsegMaxCount=index;break;}++numAllocated;}// Teststatic_assert(SOCKET_LIMIT_MIN>=32U,"Minimum Socket Limit is >= 32");while(gMaxCount<=numAllocated){int32_trv=PR_Poll(pfd,gMaxCount,PR_MillisecondsToInterval(0));SOCKET_LOG(("Socket Limit Test poll() size=%d rv=%d\n",gMaxCount,rv));if(rv>=0)break;SOCKET_LOG(("Socket Limit Test poll confirmationSize=%d rv=%d error=%d\n",gMaxCount,rv,PR_GetError()));gMaxCount-=32;if(gMaxCount<=SOCKET_LIMIT_MIN){gMaxCount=SOCKET_LIMIT_MIN;break;}}// Freefor(uint32_tindex=0;index<numAllocated;++index)if(pfd[index].fd)PR_Close(pfd[index].fd);Telemetry::Accumulate(Telemetry::NETWORK_PROBE_MAXCOUNT,gMaxCount);SOCKET_LOG(("Socket Limit Test max was confirmed at %d\n",gMaxCount));}#endif // windowsPRStatusnsSocketTransportService::DiscoverMaxCount(){gMaxCount=SOCKET_LIMIT_MIN;#if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX)// On unix and os x network sockets and file// descriptors are the same. OS X comes defaulted at 256,// most linux at 1000. We can reliably use [sg]rlimit to// query that and raise it if needed.structrlimitrlimitData;if(getrlimit(RLIMIT_NOFILE,&rlimitData)==-1)// rlimit broken - use minreturnPR_SUCCESS;if(rlimitData.rlim_cur>=SOCKET_LIMIT_TARGET){// larger than target!gMaxCount=SOCKET_LIMIT_TARGET;returnPR_SUCCESS;}int32_tmaxallowed=rlimitData.rlim_max;if((uint32_t)maxallowed<=SOCKET_LIMIT_MIN){returnPR_SUCCESS;// so small treat as if rlimit is broken}if((maxallowed==-1)||// no hard cap - ok to set target((uint32_t)maxallowed>=SOCKET_LIMIT_TARGET)){maxallowed=SOCKET_LIMIT_TARGET;}rlimitData.rlim_cur=maxallowed;setrlimit(RLIMIT_NOFILE,&rlimitData);if((getrlimit(RLIMIT_NOFILE,&rlimitData)!=-1)&&(rlimitData.rlim_cur>SOCKET_LIMIT_MIN)){gMaxCount=rlimitData.rlim_cur;}#elif defined(XP_WIN) && !defined(WIN_CE)// >= XP is confirmed to have at least 1000static_assert(SOCKET_LIMIT_TARGET<=1000,"SOCKET_LIMIT_TARGET max value is 1000");gMaxCount=SOCKET_LIMIT_TARGET;#else// other platforms are harder to test - so leave at safe legacy value#endifreturnPR_SUCCESS;}// Used to return connection info to Dashboard.cppvoidnsSocketTransportService::AnalyzeConnection(nsTArray<SocketInfo>*data,structSocketContext*context,boolaActive){if(context->mHandler->mIsPrivate)return;PRFileDesc*aFD=context->mFD;PRFileDesc*idLayer=PR_GetIdentitiesLayer(aFD,PR_NSPR_IO_LAYER);NS_ENSURE_TRUE_VOID(idLayer);booltcp=PR_GetDescType(idLayer)==PR_DESC_SOCKET_TCP;PRNetAddrpeer_addr;PodZero(&peer_addr);PRStatusrv=PR_GetPeerName(aFD,&peer_addr);if(rv!=PR_SUCCESS)return;charhost[64]={0};rv=PR_NetAddrToString(&peer_addr,host,sizeof(host));if(rv!=PR_SUCCESS)return;uint16_tport;if(peer_addr.raw.family==PR_AF_INET)port=peer_addr.inet.port;elseport=peer_addr.ipv6.port;port=PR_ntohs(port);uint64_tsent=context->mHandler->ByteCountSent();uint64_treceived=context->mHandler->ByteCountReceived();SocketInfoinfo={nsCString(host),sent,received,port,aActive,tcp};data->AppendElement(info);}voidnsSocketTransportService::GetSocketConnections(nsTArray<SocketInfo>*data){MOZ_ASSERT(OnSocketThread(),"not on socket thread");for(uint32_ti=0;i<mActiveCount;i++)AnalyzeConnection(data,&mActiveList[i],true);for(uint32_ti=0;i<mIdleCount;i++)AnalyzeConnection(data,&mIdleList[i],false);}#if defined(XP_WIN)voidnsSocketTransportService::StartPollWatchdog(){// Start off the timer from a runnable off of the main thread in order to// avoid a deadlock, see bug 1370448.RefPtr<nsSocketTransportService>self(this);NS_DispatchToMainThread(NS_NewRunnableFunction("nsSocketTransportService::StartPollWatchdog",[self]{MutexAutoLocklock(self->mLock);// Poll can hang sometimes. If we are in shutdown, we are going to start a// watchdog. If we do not exit poll within REPAIR_POLLABLE_EVENT_TIME// signal a pollable event again.MOZ_ASSERT(gIOService->IsNetTearingDown());if(self->mPolling&&!self->mPollRepairTimer){self->mPollRepairTimer=do_CreateInstance(NS_TIMER_CONTRACTID);self->mPollRepairTimer->Init(self,REPAIR_POLLABLE_EVENT_TIME,nsITimer::TYPE_REPEATING_SLACK);}}));}voidnsSocketTransportService::DoPollRepair(){MutexAutoLocklock(mLock);if(mPolling&&mPollableEvent){mPollableEvent->Signal();}elseif(mPollRepairTimer){mPollRepairTimer->Cancel();}}voidnsSocketTransportService::StartPolling(){MutexAutoLocklock(mLock);mPolling=true;}voidnsSocketTransportService::EndPolling(){MutexAutoLocklock(mLock);mPolling=false;if(mPollRepairTimer){mPollRepairTimer->Cancel();}}#endif}// namespace net}// namespace mozilla